package com.perceptivesoftware.licensing.client.common.util;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import com.extjs.gxt.ui.client.GXT;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.event.MessageBoxEvent;
import com.extjs.gxt.ui.client.widget.Component;
import com.extjs.gxt.ui.client.widget.MessageBox;
import com.extjs.gxt.ui.client.widget.button.Button;
import com.extjs.gxt.ui.client.widget.form.Field;

/**
 * Generic utilities; these are available to all clients and the server. Because
 * some clients may be importing this utility, but may not be importing the
 * domain model, please resist adding entity/dao calls here.
 *
 * <p/>
 * Copyright 2012 Perceptive Software
 * <p/>
 * Project: Perceptive Licensing
 *
 * @author Nolan Brassard
 *
 */
public class Utils
{
	public static final int PIXEL_DIVISOR = 15;

	public static boolean isY(final String s)
	{
		if (s == null)
		{
			return false;
		}
		return (s.trim().equals("Y"));
	}

	public static boolean isN(final String s)
	{
		if (s == null)
		{
			return false;
		}
		return (s.trim().equals("N"));
	}

	public static String replaceCharAt(final String s, final int pos, final char c)
	{
		if (pos >= s.length())
		{
			throw new RuntimeException("Cannot access position " + pos + " of '" + s + "'");
		}
		return s.substring(0, pos) + c + s.substring(pos + 1);
	}

	public static String implode(final String[] ary, final String delim)
	{
		final StringBuffer sb = new StringBuffer();
		for (int i = 0; i < ary.length; i++)
		{
			if (i != 0)
			{
				sb.append(delim);
			}
			sb.append(ary[i]);
		}
		return sb.toString();
	}

	public static String getYOrNull(final Boolean bool)
	{
		if (bool)
		{
			return "Y";
		}
		else
		{
			return null;
		}
	}

	public static String getYOrNull(final String in)
	{
		if (in == null)
		{
			return null;
		}
		else
		{
			if (in.equals("Y"))
			{
				return "Y";
			}
			else
			{
				return null;
			}
		}
	}

	public static void disableTabbingField(final Field<?> f)
	{
		f.setTabIndex(99999999);
	}

	/*
	 * public static void disableTabbingFields(Field[] fields) { for (final
	 * Field f : fields) { disableTabbingField(f); } }
	 */

	public static void disableTabbingButton(final Button b)
	{
		b.setTabIndex(99999999);
	}

	public static void disableTabbingButtons(final Button[] buttons)
	{
		for (final Button b : buttons)
		{
			disableTabbingButton(b);
		}
	}

	public static void disableTabbingComponent(final Component c)
	{
		if (c.el() != null)
		{
			c.el().setTabIndex(-1);
			// else
			// {
			// Window.alert("el not set for component: " + c);
			// }
		}
	}

	public static void disableTabbingComponent(final Component[] components)
	{
		for (final Component c : components)
		{
			disableTabbingComponent(c);
		}
	}

	public static String padWithLeftZeroes(final Object inVal, final int len)
	{
		String retVal = inVal.toString();
		while (retVal.length() < len)
		{
			retVal = "0" + retVal;
		}
		return retVal;
	}

	/**
	 * @param oldList
	 *            : old version of list
	 * @param newList
	 *            : new version of same list
	 * @return true if and only if new version contains an item not in old
	 *         version.
	 */
	public static boolean listContainsNewItem(final List<Object> oldList, final List<Object> newList)
	{
		if (newList == null)
		{
			return false;
		}
		if (oldList == null)
		{
			if (newList != null)
			{
				return true;
			}
			else
			{
				return false;
			}
		}
		for (final Object obj : newList)
		{
			if (!oldList.contains(obj))
			{
				return true;
			}
		}
		return false;
	}

	// convert pre-NW-6.0 size and pos values to pixel values
	// As of 6/08, the meaning of the 8-pixel offset was unknown
	public static int getPixelConversion(final int origVal)
	{
		return (origVal / PIXEL_DIVISOR);
	}

	public static Long undoPixelConversion(final int origVal)
	{
		return new Long(origVal * PIXEL_DIVISOR);
	}

	// @browserspecific
	public static void inline(final Component[] components)
	{
		if (GXT.isIE6 || GXT.isIE7)
		{
			for (final Component component : components)
			{
				component.setStyleAttribute("display", "inline");
			}
		}
		else if (GXT.isIE8)
		{
			for (final Component component : components)
			{
				component.setStyleAttribute("display", "inline");
				component.setStyleAttribute("float", "left");
			}
		}
		else
		{
			for (final Component component : components)
			{
				component.setStyleAttribute("display", "inline-table");
			}
		}
	}

	public static String convertMicrosoftColorToHTMLColor(final long decimalColor)
	{
		String hexColor = Long.toHexString(decimalColor);
		hexColor = Utils.zeroFill(hexColor, 6);
		// for some reason, Microsoft seems to use Blue-Green-Red instead of
		// Red-Green-Blue (RGB)
		return hexColor.substring(4, 6) + hexColor.substring(2, 4) + hexColor.substring(0, 2);
	}

	public static void dump(final ArrayList<String[]> arr)
	{
		for (final String[] row : arr)
		{
			final StringBuffer out = new StringBuffer();
			for (final String s : row)
			{
				out.append(s + ", ");
			}
		}
	}

	public static boolean hasVal(final String s)
	{
		return ((s != null) && (s.trim().length() > 0));
	}

	// redirector
	public static native void redirectToUrl(String url)
	/*-{
		$wnd.location = url;
	}-*/;

	public static boolean equalsOneOf(final String test, final String[] vals)
	{
		if (test == null)
		{
			for (final String s : vals)
			{
				if (s == null)
				{
					return true;
				}
			}
		}
		else
		{
			for (final String s : vals)
			{
				if ((s != null) && (test.equals(s)))
				{
					return true;
				}
			}
		}
		return false;
	}

	public static String zeroFill(final String s, final int length)
	{
		if (s == null)
		{
			return null;
		}
		final StringBuffer sb = new StringBuffer(s);
		while (sb.length() < length)
		{
			sb.insert(0, "0");
		}
		return sb.toString();
	}

	// public static void debugMessage(String message)
	// {
	// eb.publish(new MessageEvent(MessageType.DEBUG, message));
	// }

	public static String afterLastDot(final String in)
	{
		final String[] s = in.split("\\.");
		return s[s.length - 1];
	}

	public static String fileSystemSeperator()
	{
		if (GXT.isMac || GXT.isLinux)
		{
			return "/";
		}
		else
		{
			return "\\";
		}
	}

	@Deprecated
	public static Date getDateWithNoMilliseconds()
	{
		final Date d = new Date();
		final Date d2 = new Date(Utils.getYear(d), Utils.getMonth(d), Utils.getDate(d), Utils.getHours(d), Utils.getMinutes(d), Utils.getSeconds(d));
		return d2;
	}

	@SuppressWarnings("deprecation")
	public static int getDate(final Date inDate)
	{
		return inDate.getDate();
	}

	@SuppressWarnings("deprecation")
	public static int getMonth(final Date inDate)
	{
		return inDate.getMonth();
	}

	@SuppressWarnings("deprecation")
	public static int getYear(final Date inDate)
	{
		return inDate.getYear();
	}

	@SuppressWarnings("deprecation")
	public static int getHours(final Date inDate)
	{
		return inDate.getHours();
	}

	@SuppressWarnings("deprecation")
	public static int getMinutes(final Date inDate)
	{
		return inDate.getMinutes();
	}

	@SuppressWarnings("deprecation")
	public static int getSeconds(final Date d)
	{
		return d.getSeconds();
	}

	// public static DatabaseDialect getDatabaseDialect(String sDialect)
	// {
	// final String dialect = sDialect.toLowerCase();
	// if (dialect.indexOf("oracle") > -1)
	// {
	// return DatabaseDialect.ORACLE;
	// } else if (dialect.indexOf("sqlserver") > -1)
	// {
	// return DatabaseDialect.SQLSERVER;
	// } else if (dialect.indexOf("informix") > -1)
	// {
	// return DatabaseDialect.INFORMIX;
	// } else if (dialect.indexOf("db2") > -1)
	// {
	// return DatabaseDialect.DB2;
	// }
	// throw new RuntimeException("Database Dialect not handled: " + sDialect);
	// }

	public static String getStackTrace(final Throwable e)
	{
		String output = "";
		for (final StackTraceElement line : e.getStackTrace())
		{
			output += line + "(" + line.getMethodName() + "\n";
		}
		return output;
	}

	private static boolean isNotNullAndNotNegative(final String inVal)
	{
		return !(inVal == null || inVal.length() == 0 || Long.valueOf(inVal) < 0);
	}

	public static String getHexColorStringOrNullFromNW5ColorString(final String inStr)
	{
		if (!isNotNullAndNotNegative(inStr))
		{
			return null;
		}
		final long decimalColor = Long.valueOf(inStr);
		if (decimalColor >= 0)
		{
			return Utils.convertMicrosoftColorToHTMLColor(decimalColor);
		}
		return null;
	}

	public static void ifMicrosoftColorIsNotNullAndNotNegativeSetStyleAttributeToHexEquivalent(final String v5Color, final String styleAttribute, final Component component)
	{
		final String newColor = getHexColorStringOrNullFromNW5ColorString(v5Color);
		if (newColor != null)
		{
			component.setStyleAttribute(styleAttribute, "#" + newColor);
		}
	}

	public static String escapeSingleQuotes(final String inStr)
	{
		if (inStr == null)
		{
			return null;
		}
		final String retVal = inStr.replaceAll("'", "''");
		return retVal;
	}

	public static String replaceDateAndUser(final String stmpvalText, final String userId)
	{
		final Date d = new Date();
		return stmpvalText.replace("%x", getMMDDYYYYString(d)).replace("%X", getHHMMString(d)).replace("%U", userId);
	}

	private static CharSequence getHHMMString(final Date d)
	{
		return (d.getHours() + ":" + padWithLeftZeroes(new Long(d.getMinutes()), 2));
	}

	private static String getMMDDYYYYString(final Date date)
	{
		return ((date.getMonth() + 1) + "/" + (date.getDate()) + "/" + (date.getYear() + 1900));
	}

	public static String arrayToString(final String[] a, final String separator)
	{
		final StringBuffer result = new StringBuffer();
		if (a.length > 0)
		{
			result.append(a[0]);
			for (int i = 1; i < a.length; i++)
			{
				result.append(separator);
				result.append(a[i]);
			}
		}
		return result.toString();
	}

	static String REGULAR_EXPRESSION_SPECIAL_CHARS = "[\\^$.|?*+()";

	public static boolean isNullOrEmpty(final String dbid)
	{
		if (dbid == null)
		{
			return true;
		}
		else if (dbid.equals(""))
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	public static String addEscapes(final String s)
	{
		if (s == null)
		{
			return null;
		}
		final StringBuffer sb = new StringBuffer();
		String one;
		for (int i = 0; i < s.length(); i++)
		{
			one = s.substring(i, i + 1);
			if (REGULAR_EXPRESSION_SPECIAL_CHARS.contains(one))
			{
				sb.append("\\");
			}
			sb.append(one);
		}
		// System.out.println(" in:" + s + "@");
		// System.out.println("out:" + sb + "@");
		return sb.toString();
	}

	public static MessageBox yesNoCancelMessageBox(final String title, final String msg, final Listener<MessageBoxEvent> callback)
	{
		final MessageBox box = new MessageBox();
		box.setTitle(title);
		box.setMessage(msg);
		box.addCallback(callback);
		box.setIcon(MessageBox.QUESTION);
		box.setButtons(MessageBox.YESNOCANCEL);
		box.show();
		return box;
	}

	public static char charOneIfTrueZeroIfFalse(final Boolean hasPermission)
	{
		String s;
		if (hasPermission)
		{
			s = "1";
		}
		else
		{
			s = "0";
		}
		return s.toCharArray()[0];
	}

	public static String stripLeadingCharacters(final String s, final char[] leadingCharactersToStrip)
	{
		boolean goodChar;
		if (s == null)
		{
			return null;
		}
		for (int i = 0; i < s.length(); i++)
		{
			goodChar = true;
			for (final char c : leadingCharactersToStrip)
			{
				if (s.charAt(i) == c)
				{
					goodChar = false;
				}
			}
			if (goodChar)
			{
				return s.substring(i);
			}
		}
		return null;
	}

	// public static void setRoleCookie(String roleValCode)
	// {
	// if (roleValCode == null)
	// {
	// Cookies.setCookie(ClientConstants.CHANGETO_ROLEVAL_COOKIE_NAME, "", new
	// Date(), null, "/", false);
	// }
	// else
	// {
	// Cookies.setCookie(ClientConstants.CHANGETO_ROLEVAL_COOKIE_NAME,
	// roleValCode, null, null, "/", false);
	// }
	// }

	// public static Long getRoleCodeFromCookieAndClearIt()
	// {
	// final String roleValCode =
	// Cookies.getCookie(ClientConstants.CHANGETO_ROLEVAL_COOKIE_NAME);
	// setRoleCookie(null);
	// Long newRoleValCode = null;
	// if (roleValCode != null)
	// {
	// try
	// {
	// newRoleValCode = new Long(roleValCode);
	// } catch (final Exception e)
	// {
	// }
	// // if the conversion fails (it shouldnt, it should only be null
	// // or a long value) just go default
	// }
	// return newRoleValCode;
	// }

	public static String removeLegacyStrings(final String s)
	{
		String ret = "";
		if (s == null)
		{
			return null;
		}
		else
		{
			ret = s.replaceAll("~}lt}", "<").replaceAll("~}gt}", ">").replaceAll("~}am}", "&").replaceAll("~}dq}", "\"").replaceAll("~}crlf}", " ");
		}
		return ret;
	}

	/*
	 * returns true if strings are equal. improvement over .equals because null
	 * and null are equal and won't throw an NPE if one is null
	 */
	public static boolean equalsNullAware(final Object one, final Object two)
	{
		if (one == null && two == null) // both null, therefore equal
		{
			return true;
		}
		if (one == null || two == null) // from first check we know one is not
			// null, now we know one is, so they are
			// not equal
		{
			return false;
		}
		return one.equals(two);// at this point we know that neither are null,
		// simply compare them.
	}

	public static boolean isBrianBox()
	{
		return false;
	}

	public static String implode(List<String> ary, String delim)
	{
		return implode(ary.toArray(new String[] {}), delim);
	}
}